/*************************************************************************
	> File Name: decrypt.cpp
	> Author: xuwenlong
	> Mail: myxuan475@126.com 
	> Created Time: 2018年10月17日 星期三 14时25分23秒
 ************************************************************************/
#include "decrypt.h"
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <stdlib.h>


/* sz_in_buff 输入字符串
*  key 为密钥
*  iv为偏移量
*  sz_out_buff 加密输出字符串
*/
int aes_encrypt_pkcs5pading(unsigned char *sz_in_buff, int sz_in_len, unsigned char *key,unsigned char *iv, unsigned char *sz_out_buff)
{
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();

    int isSuccess = 0;
    int outl = 0;

    EVP_CIPHER_CTX_init(ctx);

    EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
    EVP_CIPHER_CTX_set_padding(ctx, 1);

    isSuccess = EVP_EncryptUpdate(ctx, sz_out_buff, &outl,sz_in_buff,sz_in_len);
    if(!isSuccess)
    {
        printf("EVP_EncryptUpdate() failed");
        EVP_CIPHER_CTX_cleanup(ctx);
        return 0;
    }
    int last = 0;
    isSuccess = EVP_EncryptFinal_ex(ctx,sz_out_buff + outl,&last);
    if(!isSuccess)
    {
        printf("EVP_EncryptUpdate() failed");
        EVP_CIPHER_CTX_cleanup(ctx);
        return 0;
    }
    outl += last;
    EVP_CIPHER_CTX_cleanup(ctx);
    EVP_CIPHER_CTX_free(ctx);
    return outl;
}

//---------------------
//作者：viewsky11
//来源：CSDN
//原文：https://blog.csdn.net/viewsky11/article/details/78983234
//版权声明：本文为博主原创文章，转载请附上博文链接！

UtilsCrypt::UtilsCrypt(const std::string &key_, MODE mode_)
{
    private_key = key_;
    mode = mode_;
}

UtilsCrypt::~UtilsCrypt()
{
    if (ctx == NULL) return;
    EVP_CIPHER_CTX_cleanup(ctx);
    EVP_CIPHER_CTX_free(ctx);
    ctx = NULL;
}

bool UtilsCrypt::InitCrypt()
{
    unsigned char iv[AES_BLOCK_SIZE];
    ctx = EVP_CIPHER_CTX_new();
    //初始化
    memset(iv,0,AES_BLOCK_SIZE);
    memcpy(iv,private_key.c_str(),AES_BLOCK_SIZE);
    //初始化ctx，加密算法初始化
    EVP_CIPHER_CTX_init(ctx);
    int isSuccess = EVP_EncryptInit_ex(ctx,EVP_aes_128_cbc(),NULL,iv,iv);
    if(!isSuccess) {
        printf("EVP_DecryptInit_ex() failed");
        EVP_CIPHER_CTX_cleanup(ctx);
        return false;
    }

    //解密数据
    EVP_CIPHER_CTX_set_padding(ctx,1);
    return true;
}

std::string UtilsCrypt::Encrypt(const char *data,int len)
{
    unsigned char sz_out_buff[560] = {0};
    int outl = 0;
    int isSuccess = EVP_EncryptUpdate(ctx, sz_out_buff, &outl,(const unsigned char*)data,len);
    if(!isSuccess)
        return "";
    return std::string((char *)sz_out_buff,outl);
}

std::string UtilsCrypt::Decrypt(const std::string &str)
{
#if 0
    char *out;
    unsigned char iv[AES_BLOCK_SIZE];
    int length = 0;

    //初始化
    memset(iv,0,AES_BLOCK_SIZE);
    memcpy(iv,private_key.c_str(),AES_BLOCK_SIZE);
    length = ((str.length() + AES_BLOCK_SIZE-1)/AES_BLOCK_SIZE)*AES_BLOCK_SIZE;
    out = (char *)malloc(length);
    int len = aes_decrypt_pkcs5pading((unsigned char*)str.c_str(),str.length(),iv,iv,(unsigned char *)out);
    if (len <= 0)
        return "";
    std::string strout(out,len);
    free(out);
    return strout;
#endif
}

std::string UtilsCrypt::FinalEncrypt()
{
    unsigned char sz_out_buff[560] = {0};
    int last = 0;
    int isSuccess = EVP_EncryptFinal_ex(ctx, sz_out_buff, &last);
    if (!isSuccess) {
        return "";
    }
    return std::string((char*)sz_out_buff,last);
}

//std::string UtilsCrypt::Encrypt(const unsigned char *data, int len)
//{
//    unsigned char *result;
//    unsigned char iv[AES_BLOCK_SIZE];
//    AES_KEY en_key;
//    int length = 0;

//    //初始化
//    memset(iv,0,AES_BLOCK_SIZE);
//    memcpy(iv,private_key.c_str(),AES_BLOCK_SIZE);
////    des_setparity(key);
//    length = ((len + AES_BLOCK_SIZE-1)/AES_BLOCK_SIZE)*AES_BLOCK_SIZE;

//    std::string str((char*)data,len);
//    for (int i = len;i < length;i++) {
//        str+='\n';
//    }

//    result = (unsigned char *)malloc(length);

//    memset(result,0,length);

//    AES_set_encrypt_key((unsigned char*)private_key.c_str(),AES_BLOCK_SIZE*8,&en_key);

//    if (mode == cbc)
//        AES_cbc_encrypt((unsigned char*)str.c_str(),result,length,&en_key,iv,AES_ENCRYPT);
//    else if (mode == ecb)
//        AES_ecb_encrypt((unsigned char*)str.c_str(),result,&en_key,AES_ENCRYPT);

//    std::string encrypt;
//    encrypt.append((char *)result,length);
//    delete result;
//    return encrypt;
//}

int UtilsCrypt::Decrypt(const char *data, int len,char* &out)
{
    unsigned char iv[AES_BLOCK_SIZE];
    AES_KEY en_key;
    int olen = 0;

    //初始化
    memset(iv,0,AES_BLOCK_SIZE);
    memcpy(iv,private_key.c_str(),AES_BLOCK_SIZE);
//    des_setparity(key);
    olen = ((len + AES_BLOCK_SIZE-1)/AES_BLOCK_SIZE)*AES_BLOCK_SIZE;
    out = (char *)malloc(olen+1);

    memset(out,0,olen);

    AES_set_decrypt_key((unsigned char *)private_key.c_str(),AES_BLOCK_SIZE*8,&en_key);

    if (mode == cbc)
        AES_cbc_encrypt((unsigned char*)data,(unsigned char*)out,len,&en_key,iv,AES_DECRYPT);
    else if (mode == ecb)
        AES_ecb_encrypt((unsigned char*)data,(unsigned char*)out,&en_key,AES_DECRYPT);
    return olen;
}
